/// 编写自动化测试
/*
Rust 中的测试函数是用来验证非测试代码是否按照期望的方式运行的。测试函数体通常执行如下三种操作：
    设置任何所需的数据或状态
    运行需要测试的代码
    断言其结果是我们所期望的
让我们看看 Rust 提供的专门用来编写测试的功能：test 属性、一些宏和 should_panic 属性。

Rust 中的测试就是一个带有 test 属性标注的函数。属性（attribute）是关于 Rust 代码片段的元数据；
第 5 章中结构体中用到的 derive 属性就是一个例子。为了将一个函数变成测试函数，需要在 fn 行之前加上 #[test]。
当使用 cargo test 命令运行测试时，Rust 会构建一个测试执行程序用来调用标记了 test 属性的函数，
并报告每一个测试是通过还是失败。
*/
#[cfg(test)]
mod tests {

    // #[test]：这个属性表明这是一个测试函数
    // 每一个测试都在一个新线程中运行，当主线程发现测试线程异常了，就将对应测试标记为失败。
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}



/// 自定义失败信息
pub fn greeting(name: &str) -> String {
    format!("Hello {}!", name)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn greeting_contains_name() {
        let result = greeting("Carol");
        assert!(
            result.contains("Carol"),
            "Greeting did not contain name, value was `{}`", result
        );
    }
}


/// 忽略某些测试
// 有时一些特定的测试执行起来是非常耗费时间的，所以在大多数运行 cargo test 的时候希望能排除他们。
// 虽然可以通过参数列举出所有希望运行的测试来做到，也可以使用 ignore 属性来标记耗时的测试并排除他们，
#[test]
#[ignore]
fn expensive_test() {
    // 需要运行一个小时的代码
}


/// 测试的组织结构
/*
测试是一个复杂的概念，而且不同的开发者也采用不同的技术和组织。Rust 社区倾向于根据测试的两个主要分类来考虑问题：
单元测试（unit tests）与 集成测试（integration tests）。单元测试倾向于更小而更集中，
在隔离的环境中一次测试一个模块，或者是测试私有接口。而集成测试对于你的库来说则完全是外部的。
它们与其他外部代码一样，通过相同的方式使用你的代码，只测试公有接口而且每个测试都有可能会测试多个模块。
为了保证你的库能够按照你的预期运行，从独立和整体的角度编写这两类测试都是非常重要的。
*/
/// 单元测试
/*
单元测试的目的是在与其他部分隔离的环境中测试每一个单元的代码，以便于快速而准确的某个单元的代码功能是否符合预期。
单元测试与他们要测试的代码共同存放在位于 src 目录下相同的文件中。规范是在每个文件中创建包含测试函数的 tests 模块，
并使用 cfg(test) 标注模块。
*/
/// 测试模块和 #[cfg(test)]
/*
测试模块的 #[cfg(test)] 标注告诉 Rust 只在执行 cargo test 时才编译和运行测试代码，
而在运行 cargo build 时不这么做。这在只希望构建库的时候可以节省编译时间，并且因为它们并没有包含测试，
所以能减少编译产生的文件的大小。与之对应的集成测试因为位于另一个文件夹，所以它们并不需要 #[cfg(test)] 标注。
然而单元测试位于与源码相同的文件中，所以你需要使用 #[cfg(test)] 来指定他们不应该被包含进编译结果中。
*/


/// 集成测试
/*
集成测试的目的是测试库的多个部分能否一起正常工作。一些单独能正确运行的代码单元集成在一起也可能会出现问题，
所以集成测试的覆盖率也是很重要的。为了创建集成测试，你需要先创建一个 tests 目录。
*/
/// tests 目录
/*
为了编写集成测试，需要在项目根目录创建一个 tests 目录，与 src 同级。Cargo 知道如何去寻找这个目录中的集成测试文件。
接着可以随意在这个目录中创建任意多的测试文件，Cargo 会将每一个文件当作单独的 crate 来编译。
*/